package com.killer.factory;

import com.killer.handler.RpcClientHandler;
import com.killer.rpc.RpcEncoder;
import com.killer.rpc.RpcRequest;
import com.killer.serializer.JsonSerializer;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.UUID;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 对象工厂，用来生产服务端对应的代理对象，进行远程调用
 */
public class RpcFactory {

    /**
     * 设置成单例
     */
    private static RpcFactory rpcFactory=new RpcFactory();

    public static RpcFactory getRpcFactory(){
        return rpcFactory;
    }

    private RpcFactory(){}

    private RpcClientHandler rpcClientHandler;

    /**
     * 构建一个全局的线程池对象，用于进行异步的远程调用
     */
    private static ExecutorService executorService= Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());


    public <T> T getObject(final Class<T> clazz) {
        return (T) Proxy.newProxyInstance(RpcFactory.class.getClassLoader(), new Class[]{clazz}, new InvocationHandler() {
            //通过socket的方式进行远程调用
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (rpcClientHandler == null) {
                    init();
                }
                //构建RpcRequest对象
                RpcRequest rpcRequest = buildRpcRequest(clazz, method, args);
                //设置对应的rpcRequest对象
                rpcClientHandler.setRpcRequest(rpcRequest);
                //通过线程池异步远程调用
                return executorService.submit(rpcClientHandler).get();
            }
        });
    }

    private RpcRequest buildRpcRequest(Class<?> clazz, Method method, Object[] args) {
        RpcRequest rpcRequest=new RpcRequest();
        rpcRequest.setRequestId(UUID.randomUUID().toString());
        rpcRequest.setClassName(clazz.getName());
        rpcRequest.setMethodName(method.getName());
        rpcRequest.setParams(args);
        Class<?>[] paramTypes = new Class<?>[args.length];
        for (int i = 0; i < args.length; i++) {
            paramTypes[i]=args[i].getClass();
        }
        rpcRequest.setParamTypes(paramTypes);
        return rpcRequest;
    }

    public void init() throws InterruptedException {
        rpcClientHandler=new RpcClientHandler();
        //创建线程组
        EventLoopGroup group = new NioEventLoopGroup();
        //创建启动引导类
        Bootstrap bootstrap=new Bootstrap();
        //配置启动引导类
        bootstrap.group(group)
                //设置通道类型
                .channel(NioSocketChannel.class)
                //设置参数
                .option(ChannelOption.TCP_NODELAY,true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        //添加自定编码器用于编码发送的rpc请求
                        pipeline.addLast(new RpcEncoder(new JsonSerializer()));
                        //添加String解码器用于解码服务器返回的数据
                        pipeline.addLast(new StringDecoder());
                        //添加客户端RPC处理类
                        pipeline.addLast(rpcClientHandler);
                    }
                });
        //发起异步连接操作
        ChannelFuture channelFuture = bootstrap.connect("localhost", 8888).sync();
        //等待客户端链路关闭
        //channelFuture.channel().closeFuture().sync();

    }
}
